package com.zzyl.nursing.service.impl;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.UserThreadLocal;
import com.github.pagehelper.PageHelper;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.common.utils.UserThreadLocal;
import com.zzyl.framework.web.service.TokenService;
import com.zzyl.nursing.domain.*;
import com.zzyl.nursing.domain.Elder;
import com.zzyl.nursing.dto.*;
import com.zzyl.nursing.dto.MemberElderDto;
import com.zzyl.nursing.mapper.ElderMapper;
import com.zzyl.nursing.mapper.FamilyMemberMapper;
import com.zzyl.nursing.service.*;
import com.zzyl.nursing.service.IElderService;
import com.zzyl.nursing.vo.DeviceDataGraphVo;
import com.zzyl.nursing.vo.ElderVO;
import com.zzyl.nursing.vo.FamilyMemberElderVo;
import com.zzyl.nursing.vo.LoginVo;
import org.apache.poi.ss.formula.functions.T;
import com.zzyl.nursing.vo.MemberElderVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.parameters.P;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 老人家属Service业务层处理
 *
 * @author ruoyi
 * @date 2024-09-19
 */
@Service
public class FamilyMemberServiceImpl extends ServiceImpl<FamilyMemberMapper, FamilyMember> implements IFamilyMemberService {
    @Autowired
    private FamilyMemberMapper familyMemberMapper;
    @Autowired
    private IElderService elderService;

    @Autowired
    private WechatService wechatService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IContractService contractService;

    @Autowired
    private IDeviceService deviceService;

    static List<String> DEFAULT_NICK_NAME = ListUtil.of(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝");

    /**
     * 小程序登录
     *
     * @param dto
     * @return
     */
    @Override
    public LoginVo login(UserLoginRequestDto dto) {

        //1.获取openid(调用微信的接口获取) ***
        String openid = wechatService.getOpenid(dto.getCode());

        //2.根据openid查询用户
        LambdaQueryWrapper<FamilyMember> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FamilyMember::getOpenId, openid);
        FamilyMember familyMember = getOne(queryWrapper);

        //3.判断用户是否存在，用户不存在，就构建用户
        if (ObjectUtil.isEmpty(familyMember)) {
            /*familyMember = new FamilyMember();
            familyMember.setOpenId(openid);*/
            familyMember = FamilyMember.builder()
                    .openId(openid)
                    .build();
        }

        //4.获取用户的手机号（调用微信的接口获取）***
        String phone = wechatService.getPhone(dto.getPhoneCode());

        //5. 新增或修改用户
        inserOrUpdateFamilyMember(familyMember, phone);

        //6. 把用户的信息封装到token,返回
        Map<String, Object> claims = new HashMap<>();
        claims.put("username", familyMember.getName());
        claims.put("userId", familyMember.getId());
        String token = tokenService.createToken(claims);

        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(familyMember.getName());

        return loginVo;
    }


    /**
     * 绑定家人
     */
    @Override
    public void bindingFamily(MemberElderDto memberElderDto) {
        //获取老人身份证身份证
        String idCard = memberElderDto.getIdCard();
        if (ObjectUtil.isEmpty(idCard)) {
            //如果为空 则抛异常
            throw new BaseException("老人身份证不能为空！");
        }
        if (idCard.length() != 18) {
            //如果身份证长度不为18则抛异常
            throw new BaseException("身份证格式错误！");
        }
        //获取老人姓名
        String name = memberElderDto.getName();
        if (ObjectUtil.isEmpty(name)) {
            //为空则抛异常
            throw new BaseException("老人姓名不能为空！");
        }
        //根据老人的身份证找到对应的老人
        Elder elder = elderService.lambdaQuery().eq(Elder::getIdCardNo, idCard).one();
        //如果为空则代表该老人不存在
        if (ObjectUtil.isEmpty(elder)) {
            throw new BaseException("未查询到该老人，请检查老人是否已入住~");
        }

        //校验名字是否对得上
        if (name.equals(elder.getName())) {
            //成功则入库
            //获取小程序当前用户的id
            Long memberId = UserThreadLocal.get();
            //封装实体类
            FamilyMemberElder familyMemberElder = new FamilyMemberElder();
            familyMemberElder.setFamilyMemberId(memberId);
            familyMemberElder.setElderId(elder.getId());
            familyMemberElder.setRemark(memberElderDto.getRemark());
            try {
                familyMemberMapper.binding(familyMemberElder);
            } catch (Exception e) {
                throw new BaseException("请勿重复添加老人~");
            }
        }


    }

    /**
     * 查询家人列表
     *
     * @return
     */
    @Override
    public List<FamilyMemberElderVo> selectFamily() {

        return familyMemberMapper.selectFamily();
    }

    /**
     * 分页查询已入住老人信息
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public List<MemberElderVo> pageSelectFamily(Integer pageNum, Integer pageSize) {
        //开启分页查询
        PageHelper.startPage(pageNum, pageSize);
        //计算从第几页开始查
//        pageNum = (pageNum - 1) * pageSize;
        Long id = UserThreadLocal.get();
        //从库里查
        List<MemberElderVo> vo = familyMemberMapper.pageSelectFamily(pageNum, pageSize, id);
        return vo;
    }

    /**
     * 查询健康数据
     *
     * @param memberDeviceDto
     * @return
     */
    @Override
    public MemberDeviceVO queryDevicePropertyStatus(MemberDeviceDto memberDeviceDto) {
        //判断数据是否为空
        if (ObjectUtil.isNull(memberDeviceDto)) {
            throw new BaseException("数据异常");
        }
        //查询设备的iotId,因为设备名称不可能重复，所以根据设备名称去查询只能查询一个
        Device device = this.deviceService.lambdaQuery()
                .eq(Device::getDeviceName, memberDeviceDto.getDeviceName())
                .eq(ObjectUtil.isNotNull(memberDeviceDto.getProductKey()), Device::getProductKey, memberDeviceDto.getProductKey())
                .one();
        //从缓存中获取数据
        List<DeviceData> dataList = (List<DeviceData>) redisTemplate.opsForHash().get(CacheConstants.IOT_DEVICE_LAST_DATA, device.getIotId());
        //封装数据
        if (ObjectUtil.isEmpty(dataList)) {
            throw new BaseException("设备还没有上报数据");
        }
        //序列化
        List<DeviceData> list1 = JSONUtil.toList(dataList.toString(), DeviceData.class);
        MemberDeviceVO memberDeviceVO = new MemberDeviceVO();
        //新建装设备上报数据的集合
        List<PropertyStatusInfo> list = new ArrayList<>();
        for (DeviceData deviceData : list1) {
            //构建对象
            PropertyStatusInfo propertyStatusInfo = new PropertyStatusInfo();
            String value = deviceData.getDataValue();
            //属性赋值
            propertyStatusInfo.setIdentifier(deviceData.getFunctionId());
            propertyStatusInfo.setName(deviceData.getFunctionId());
            propertyStatusInfo.setValue(deviceData.getDataValue());
            //添加到集合
            list.add(propertyStatusInfo);
        }
        //装填
        HealthVo healthVo = new HealthVo();
        healthVo.setPropertyStatusInfo(list);
        memberDeviceVO.setList(healthVo);
        return memberDeviceVO;
    }

    /**
     * device_data
     * 新增或修改用户
     *
     * @param familyMember
     * @param phone
     */
    private void inserOrUpdateFamilyMember(FamilyMember familyMember, String phone) {

        //1. 判断新的手机跟数据库中保存的手机号是否一致
        if (ObjectUtil.notEqual(familyMember.getPhone(), phone)) {
            familyMember.setPhone(phone);
        }

        //2. id是否存在，如存在，就修改
        if (ObjectUtil.isNotEmpty(familyMember.getId())) {
            updateById(familyMember);
            return;
        }

        //3. 不存在，就新增 (拼装用户的昵称：随机字符串+手机号后4位)
        int index = (int) (Math.random() * DEFAULT_NICK_NAME.size());
        String nickName = DEFAULT_NICK_NAME.get(index) + phone.substring(phone.length() - 4);
        familyMember.setName(nickName);
        save(familyMember);
    }

    /**
     * 按日统计查询指标数据
     *
     * @param timeQueryDto
     * @return
     */
    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByDay(DayTimeQueryDto timeQueryDto) {
        if (ObjectUtil.isNull(timeQueryDto)) {
            throw new BaseException("数据异常");
        }
        //时间毫秒值转化为localDataTime类型
        Long startTime = timeQueryDto.getStartTime();
        LocalDateTime time = LocalDateTimeUtil.of(startTime);
        List<DeviceDataGraphVo> list = DeviceDataGraphVo.dayInstance(time);
        //数据库查数据
        List<DeviceDataGraphVo> deviceDataGraphVos = familyMemberMapper.queryDeviceDataListByDay(timeQueryDto.getIotId(), timeQueryDto.getFunctionId(),
                LocalDateTimeUtil.of(timeQueryDto.getStartTime()), LocalDateTimeUtil.of(timeQueryDto.getEndTime()));
//        deviceDataGraphVos.addAll(list);
        Map<String, Double> map = deviceDataGraphVos.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        list.forEach(d -> {
            Double val = map.get(d.getDateTime()) == null ? 0.0 : map.get(d.getDateTime());
            d.setDataValue(val);
        });
        return list;


    }

    /**
     * 按周统计查询指标数据
     *
     * @param timeQueryDto
     * @return
     */
    @Override
    public List<DeviceDataGraphVo> queryDeviceDataListByWeek(DayTimeQueryDto timeQueryDto) {
        //判断为不为空
        if (ObjectUtil.isNull(timeQueryDto)) {
            throw new BaseException("数据异常");
        }
        //拿到整体的集合
        List<DeviceDataGraphVo> vos = DeviceDataGraphVo.weekInstance(LocalDateTimeUtil.of(timeQueryDto.getStartTime()));
        List<DeviceDataGraphVo> deviceDataGraphVos = familyMemberMapper.queryDeviceDataListByWeek(timeQueryDto.getIotId(), timeQueryDto.getFunctionId(), LocalDateTimeUtil.of(timeQueryDto.getStartTime()), LocalDateTimeUtil.of(timeQueryDto.getEndTime()));
        Map<String, Double> map = deviceDataGraphVos.stream().collect(Collectors.toMap(DeviceDataGraphVo::getDateTime, DeviceDataGraphVo::getDataValue));
        vos.forEach(d -> {
            Double val = map.get(d.getDateTime()) == null ? 0.0 : map.get(d.getDateTime());
            d.setDataValue(val);
        });
        return vos;
    }
}
